package org.toxsoft.uskat.core.backend.api;

import static org.toxsoft.core.tslib.av.EAtomicType.*;
import static org.toxsoft.core.tslib.av.impl.AvUtils.*;
import static org.toxsoft.core.tslib.av.metainfo.IAvMetaConstants.*;

import org.toxsoft.core.tslib.av.impl.*;
import org.toxsoft.core.tslib.av.metainfo.*;
import org.toxsoft.core.tslib.bricks.events.msg.*;
import org.toxsoft.core.tslib.coll.helpers.*;
import org.toxsoft.core.tslib.gw.skid.*;
import org.toxsoft.core.tslib.utils.errors.*;
import org.toxsoft.uskat.core.api.objserv.*;

/**
 * Messages generated by {@link IBaObjects} addon to the frontend.
 *
 * @author hazard157
 */
public interface IBaObjectsMessages {

  // FIXME move to BaMsgXxx

  // ------------------------------------------------------------------------------------
  // Message: any change in the objects

  /**
   * The message ID.
   */
  String MSGID_OBJECTS_CHANGE = "ObjectsChange"; //$NON-NLS-1$

  /**
   * ID of the option {@link #OPDEF_CRUD_OP}.
   */
  String OPID_CRUD_OP = "CrudOp"; //$NON-NLS-1$

  /**
   * {@link GtMessage#args()} option: stores {@link ECrudOp}, the change kind
   */
  IDataDef OPDEF_CRUD_OP = DataDef.create( OPID_CRUD_OP, VALOBJ, //
      TSID_IS_MANDATORY, AV_TRUE, //
      TSID_KEEPER_ID, ECrudOp.KEEPER_ID //
  );

  /**
   * ID of the option {@link #OPDEF_OBJ_SKID}.
   */
  String OPID_OBJ_SKID = "ObjSkid"; //$NON-NLS-1$

  /**
   * {@link GtMessage#args()} option: stores affected object SKID or not specified for {@link ECrudOp#LIST}.
   */
  IDataDef OPDEF_OBJ_SKID = DataDef.create( OPID_OBJ_SKID, VALOBJ, //
      TSID_IS_MANDATORY, AV_FALSE, //
      TSID_KEEPER_ID, Skid.KEEPER_ID //
  );

  /**
   * Creates the {@link GtMessage} for any change in the objects.
   *
   * @param aOp {@link ECrudOp} - the change kind
   * @param aSkid {@link Skid} - affected object SKID, assumed <code>null</code> for {@link ECrudOp#LIST}
   * @return {@link GtMessage} - created instance to send to the frontend
   * @throws TsNullArgumentRtException any argument = <code>null</code>
   */
  static GtMessage makeMessage( ECrudOp aOp, Skid aSkid ) {
    TsNullArgumentRtException.checkNull( aOp );
    GtMessage msg;
    if( aOp != ECrudOp.LIST ) {
      TsNullArgumentRtException.checkNull( aSkid );
      msg = new GtMessage( ISkObjectService.SERVICE_ID, MSGID_OBJECTS_CHANGE, //
          OPID_CRUD_OP, avValobj( aOp ), //
          OPID_OBJ_SKID, avValobj( aSkid ) );
    }
    else {
      msg = new GtMessage( ISkObjectService.SERVICE_ID, MSGID_OBJECTS_CHANGE, //
          OPID_CRUD_OP, avValobj( ECrudOp.LIST ) );
    }
    return msg;
  }

  /**
   * Extracts {@link #OPDEF_CRUD_OP} value from the message with ID {@link #MSGID_OBJECTS_CHANGE}.
   *
   * @param aMsg {@link GenericMessage} - the message
   * @return {@link ECrudOp} - retreived value
   * @throws TsNullArgumentRtException any argument = <code>null</code>
   * @throws TsIllegalArgumentRtException message is not {@link #MSGID_OBJECTS_CHANGE}
   * @throws TsItemNotFoundRtException option {@link #OPID_CRUD_OP} is missed in {@link GenericMessage#args()}
   */
  static ECrudOp extractCrudOp( GenericMessage aMsg ) {
    TsNullArgumentRtException.checkNull( aMsg );
    TsIllegalArgumentRtException.checkFalse( aMsg.messageId().equals( MSGID_OBJECTS_CHANGE ) );
    return OPDEF_CRUD_OP.getValue( aMsg.args() ).asValobj();
  }

  /**
   * Extracts {@link #OPDEF_OBJ_SKID} value from the message with ID {@link #MSGID_OBJECTS_CHANGE}.
   *
   * @param aMsg {@link GenericMessage} - the message
   * @return Skid - retreived value, may be <code>null</code>
   * @throws TsNullArgumentRtException any argument = <code>null</code>
   * @throws TsIllegalArgumentRtException message is not {@link #MSGID_OBJECTS_CHANGE}
   * @throws TsIllegalArgumentRtException message is invalid
   */
  static Skid extractSkid( GenericMessage aMsg ) {
    ECrudOp op = extractCrudOp( aMsg );
    Skid skid = aMsg.args().getValobj( OPID_OBJ_SKID, null );
    if( skid != null ) {
      TsIllegalArgumentRtException.checkTrue( op == ECrudOp.LIST );
    }
    else {
      TsIllegalArgumentRtException.checkTrue( op != ECrudOp.LIST );
    }
    return skid;
  }

}
